<!-- starSky.vue 星空 -->
<template>
    <div class="container">
        <div class="wrap">
            <canvas ref='star-sky-canvas'></canvas>
            <img class='front-img' :src="pic" alt="">
        </div>
    </div>
</template>
<style scoped>
    .wrap{
        position: relative;
    }
    .front-img{
        display: block;
        border:none;
        outline: none;
        width: 800px;
        height: 200px;
        position: absolute;
        bottom: 0;
        left: 50%;
        -webkit-transform:translate(-50%,0);
        -moz-transform:translate(-50%,0);
        -ms-transform:translate(-50%,0);
        -o-transform:translate(-50%,0);
        transform:translate(-50%,0);
        z-index: 333;
    }
</style>
<script>
    import utils from '@/utils/utils.js' ;
    import BG1 from '@/assets/bg1.png' ;
    export default {
        data(){
            return {
                pic:BG1 , // 前景图片
                canvas:null, // canvas元素
                background:'#fff',
                width:800, // canvas宽度
                height:600, // canvas高度
                ctx:null , // canvas的绘制上下文
                bg:{
                    type:2, // 1 纯色， 2 渐变
                    color:'#3300ff', // 该颜色作为颜色基调，实际显示时，将该颜色降低了亮度，以降低天空亮度
                    colorAnimate:true , // 颜色变化动画是否开启
                },
                light:{ // 薄雾，光线，
                    baseY:0 , // 中心y坐标基准值
                    alpha:0.1, // 不透明度基准值
                    speed:1 ,// 移动速度基准值
                    color:'#fff' , // 颜色
                    scaleY:2, 
                    count:20, // 数量
                    minR:10 , // 最小宽度基准值，
                    maxR:50 , // 最大宽度基准值
                    list:[], // 保存了所有的光数据对象的数组
                }, 
                bgStar:{ // 背景的星星
                    count:150, // 数量
                    baseR:1.2 , // 半径基准值，波动幅度 +- 0.2倍
                    color:'#fff' , // 颜色
                    speed:0.05, // 移动速度
                    list:[], // 保存所有背景星星的列表
                },
                mousepoint:{ // 鼠标移动是产生的粒子配置
                    distance:80 , // 产生的粒子和鼠标之间的距离限制
                    r:4, // 产生的粒子的半径限制
                    minR:1, // 粒子的半径最小值
                    count:2 , // 每次产生的数量
                    color:'#fff' , // 这些粒子的颜色,如果背景的颜色动画打开了，则颜色与之对应，否则颜色是这里的颜色
                    speed:0.1 , // 移动的速度
                    alphaSpeed:0.005, // 透明度的速度 
                    list:[] // 粒子数据
                },
                animationFrame:null,
                timer:null ,
            }
        },
        methods:{
            init(){ // 初始化canvas状态
                this.canvas = this.$refs['star-sky-canvas'] ;
                this.canvas.width = this.width ;
                this.canvas.height = this.height ;
                this.canvas.style.background = this.background ;
                if(this.canvas.getContext){
                    this.ctx = this.canvas.getContext('2d') ;

                    // 薄雾的中心Y坐标初始化：
                    this.light.baseY = this.height ;
                }else{
                    this.$message('您的浏览器不支持canvas绘画环境');
                }
            },
            madeLight(){ // 薄雾
                let $vue = this ; 
                function Light(){
                    let x = Math.random()*$vue.width ; 
                    let y = $vue.light.baseY ;
                    let color = utils.HexColorToRGB($vue.light.color,$vue.light.alpha) ;
                    let r = Math.floor(Math.random()*($vue.light.maxR - $vue.light.minR + 1 ) + $vue.light.minR) ; // 最小宽度基准值 至 最大宽度基准值 之间的随机整数 ;
                    let speed = Math.random()>0.5?-1*$vue.light.speed:1*$vue.light.speed ; 
                    return {
                        x,y,color,r,speed 
                    }
                }
                for(let i=0;i<this.light.count;i++){
                    this.light.list.push(new Light())
                }
            },
            madebackgroundStar(){ // 背景的星星
                let $vue = this ;
                function BgStar(){
                    let r = Math.random()*$vue.bgStar.baseR + $vue.bgStar.baseR*0.2 ; 
                    let x = Math.random()*$vue.width ; 
                    let y = Math.random()*$vue.height ; 
                    let color = utils.HexColorToRGB($vue.bgStar.color) ;
                    let speed = $vue.bgStar.speed ; 
                    return {
                        x,y,color,r,speed
                    }
                }
                for(let i=0;i<this.bgStar.count;i++){
                    this.bgStar.list.push(new BgStar())
                }
            },
            draw(){
                this.ctx.clearRect(0,0,this.width,this.height) ;
                this.drawBg() ;
                this.drawLight() ;
                this.drawBgStar() ;
                this.drawMousepoints() ;
            },
            drawLight(){
                this.ctx.save() ;
                this.ctx.scale(1,this.light.scaleY);
                for(let i=0;i<this.light.list.length;i++){
                    let item = this.light.list[i];
                    this.ctx.beginPath() ;
                    this.ctx.rect(item.x-item.r*3,item.y/this.light.scaleY-item.r*3,item.r*6,item.r*6)
                    this.ctx.closePath() ;

                    let fill = this.ctx.createRadialGradient(item.x,item.y/this.light.scaleY,item.r/2,item.x,item.y/this.light.scaleY,item.r*3) ;

                    fill.addColorStop(0,item.color);
                    fill.addColorStop(1,utils.updateAlpha(item.color,0));
                    this.ctx.fillStyle = fill ;
                    this.ctx.fill() ;
                }
                this.ctx.restore();

                // 更新x坐标，使移动：
                this.updateLight();
            },
            drawBgStar(){
                this.ctx.save() ;
                for(let i=0;i<this.bgStar.list.length;i++){
                    let item = this.bgStar.list[i];
                    this.ctx.beginPath() ;
                    this.ctx.arc(item.x,item.y,item.r,0,2*Math.PI);
                    this.ctx.closePath() ;

                    let fill = this.ctx.createRadialGradient(item.x,item.y,item.r/2,item.x,item.y,item.r) ;
                    fill.addColorStop(0,item.color);
                    fill.addColorStop(1,utils.updateAlpha(item.color,0));
                    this.ctx.fillStyle = fill ;
                    this.ctx.fill() ;
                }
                this.ctx.restore();

                // 更新y坐标，使移动：
                this.updateBgStar();
            },
            drawBg(){ // 绘制背景色
                this.ctx.save() ;
                if(this.bg.type==2){
                    // 渐变：
                    let fill = this.ctx.createLinearGradient(0,this.height,0,0);
                    if(this.bg.colorAnimate){
                        // 启动了颜色渐变变化；
                        this.bg.color = utils.colorChange(this.bg.color,1) ; // 按照规则改变颜色rgb，实现颜色渐变
                    }
                    
                    fill.addColorStop(0,utils.colorBright(this.bg.color,-0.35)) ; // 颜色变暗35%
                    fill.addColorStop(1,utils.colorBright(this.bg.color,-0.9)) ; // 颜色变暗90%
                    this.ctx.fillStyle = fill ;
                    this.ctx.fillRect(0,0,this.width,this.height) ;
                }else{
                    // 纯色 :
                    this.ctx.fillStyle = utils.colorBright(this.bg.color,-0.6) ; // 颜色变暗70%
                    this.ctx.fillRect(0,0,this.width,this.height) ;
                }
                this.ctx.restore() ;
            },
            
            updateLight(){
                this.light.list.forEach((item,i)=>{
                    item.x = parseInt(item.x + item.speed);
                    if(item.x<0-item.r*2||item.x>this.width+item.r*2){
                        item.speed = - item.speed ;
                    }
                })
            },
            updateBgStar(){
                this.bgStar.list.forEach((item,i)=>{
                    item.y -= item.speed ;
                    if(item.y<0-item.r){
                        // 星星跑到最上面的canvas可视区之外了。重置他的xy，使他回到最下边的可视区外，且x位置也重新随机
                        item.x = Math.random()*this.width ; 
                        item.y = this.height + item.r ; 
                    }
                })
            },
            move(){
                this.draw();
                var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame ;
                if(requestAnimationFrame){
                    this.animationFrame = requestAnimationFrame(()=>{
                        this.move();
                    })
                }else{
                    this.timer = setTimeout(()=>{
                        this.move();
                    },1000/60)
                }
            },
            mousemoveHandler(e){
                let ev = e || window.event ;
                // 在鼠标坐标的方圆50px的圆形区域内随机生成点：
                this.mousepoint.list.push(...this.madeMousepoints(ev.offsetX,ev.offsetY)) ;

            },
            madeMousepoints(x,y){
                let result = [] ;
                for(let i=0;i<this.mousepoint.count;i++){
                    let distance = Math.floor(Math.random()*(this.mousepoint.distance+1)) ; // 距离鼠标的中心随机数；
                    let xDis = Math.floor(Math.random()*(distance+1)) ;  // 根据距离，随机0到distance的作为x方向的距离；
                    let yDis = Math.sqrt(Math.pow(distance,2)-Math.pow(xDis,2)) ;
                    // xDis 和 yDis 随机正负号:
                    xDis = Math.random()>0.5? xDis : -xDis ;
                    yDis = Math.random()>0.5? yDis : -yDis ;
                    let r = Math.random()*(this.mousepoint.r-this.mousepoint.minR)+this.mousepoint.minR ; // 粒子半径

                    // 随机方向的速度：
                    let xSpeed = Math.random()>0.5?Math.random()*this.mousepoint.speed : -Math.random()*this.mousepoint.speed ; 
                    let ySpeed = Math.sqrt(Math.pow(this.mousepoint.speed,2)-Math.pow(xSpeed,2)) ;
                    ySpeed = Math.random()>0.5?ySpeed:-ySpeed ; // y方向的速度分量正负号
                    
                    result.push({
                        x:x+xDis,
                        y:y+yDis,
                        r:r,
                        alpha:.7 ,
                        color:this.bg.colorAnimate?this.bg.color:this.mousepoint.color,
                        xSpeed:xSpeed , 
                        ySpeed:ySpeed , 
                        alphaSpeed:this.mousepoint.alphaSpeed 
                    })
                }
                return result ;
            },
            drawMousepoints(){
                for(let i=0;i<this.mousepoint.list.length;i++){
                    let point = this.mousepoint.list[i] ;
                    let afterPoints = [this.mousepoint.list[i+1],this.mousepoint.list[i+2],this.mousepoint.list[i+3]] ; // 后面3个粒子
                    // 点状粒子绘制：
                    this.ctx.beginPath() ;
                    this.ctx.arc(point.x,point.y,point.r,0,2*Math.PI) ;
                    this.ctx.fillStyle = utils.updateAlpha(point.color,point.alpha) ;
                    this.ctx.strokeStyle = this.ctx.fillStyle ;
                    this.ctx.fill();
                    this.ctx.closePath() ;
                    // 该点与后3个点之间连线：
                    afterPoints.forEach(p=>{
                        if(p){ // 判断后面的点是否存在，然后画线
                            this.ctx.beginPath() ;
                            this.ctx.moveTo(point.x,point.y) ;
                            this.ctx.lineTo(p.x,p.y) ;
                            this.ctx.stroke() ;
                            this.ctx.closePath() ;
                        }
                    })
                    // 更新粒子：
                    // 透明度：
                    point.alpha -= point.alphaSpeed ;
                    if(point.alpha <= 0 ){
                        this.mousepoint.list.splice(i--,1) ;
                    }

                    // 移动：
                    point.x += point.xSpeed ;
                    point.y += point.ySpeed ;
                }
            }
        },
        mounted(){ 
            this.init() ;
            if(!this.ctx) return ;
            this.madeLight() ;// 创建薄雾
            this.madebackgroundStar() ; // 创建背景星星
            this.move();
            
            // 绑定鼠标事件
            this.canvas.addEventListener('mousemove',this.mousemoveHandler,false) ;
        },
        beforeDestroy(){
            // 组件销毁时，清除定时器。
            if(this.animationFrame){
                cancelAnimationFrame(this.animationFrame) ;
                this.animationFrame = null ;
            }
            if(this.timer){
                clearTimeout(this.timer);
                this.timer = null ;
            }
            // 解除鼠标事件
            this.canvas.removeEventListener('mousemove',this.mousemoveHandler) ;
        }
    }
</script>